package com.ddwl.goods.service;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.ddwl.common.constant.BaseEnum;
import com.ddwl.common.constant.GoodsEnum;
import com.ddwl.common.exception.CommonException;
import com.ddwl.common.exception.ExceptionCode;
import com.ddwl.common.exception.ParamException;
import com.ddwl.common.feign.api.OrderApi;
import com.ddwl.common.feign.api.SearchApi;
import com.ddwl.common.util.BeanConverUtils;
import com.ddwl.common.util.MySqlUtil;
import com.ddwl.goods.dao.*;
import com.ddwl.goods.dao.bargain.BargainOrderDao;
import com.ddwl.goods.dao.model.LimitTimePurGood;
import com.ddwl.goods.dao.model.Sku;
import com.ddwl.goods.dto.ItemDiscountDto;
import com.ddwl.goods.dto.ItemReserveDto;
import com.ddwl.goods.model.DiscountItem;
import com.ddwl.goods.model.DiscountItemSku;
import com.ddwl.goods.model.Item;
import com.ddwl.goods.model.ItemTag;
import com.ddwl.goods.model.bargain.BargainOrder;
import com.ddwl.schema.bo.base.PageBo;
import com.ddwl.schema.bo.distr.ComputeProfitPriceBo;
import com.ddwl.schema.bo.goods.ItemListApiBo;
import com.ddwl.schema.bo.goods.QueryLimitTimePurGoodBo;
import com.ddwl.schema.bo.goods.SkuBo;
import com.ddwl.schema.bo.goods.SupplierBo;
import com.ddwl.schema.bo.goods.retail.DiscountItemChangeStockBo;
import com.ddwl.schema.bo.goods.retail.DiscountItemSaleBo;
import com.ddwl.schema.bo.order.ChangeStockBo;
import com.ddwl.schema.bo.order.LockStockBo;
import com.ddwl.schema.bo.order.QuerySkuPriceBo;
import com.ddwl.schema.bo.order.SkuSaleBo;
import com.ddwl.schema.vo.base.PageVo;
import com.ddwl.schema.vo.dist.ComputeProfitPriceVo;
import com.ddwl.schema.vo.goods.*;
import com.ddwl.schema.vo.order.SecondKillOrderVo;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.framework.AopContext;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.Instant;
import java.util.*;
import java.util.stream.Collectors;


/**
 * @author Fu Zhaohui
 * @version 1.0.0
 * @date 2019/8/29 19:07
 */
@Slf4j
@Service
public class SkuService {
    @Resource
    private SkuDao skuDao;
    @Resource
    private ReserveDao reserveDao;
    @Resource
    private DiscountDao discountDao;
    @Resource
    private DiscountItemDao discountItemDao;
    @Resource
    private ItemTagDao itemTagDao;
    @Resource
    private DiscountItemSkuDao discountItemSkuDao;
    @Resource
    private ItemDao itemDao;
    @Resource
    private ItemService itemService;
    @Resource
    private SupplierService supplierService;
    @Resource
    private BargainOrderDao bargainOrderDao;
    @Resource
    private OrderApi orderApi;
    @Resource
    private LimitTimePurGoodDao limitTimePurGoodDao;
    @Resource
    private LimitTimePurActiveService limitTimePurActiveService;
    @Resource
    private GoodsProfitService goodsProfitService;
    @Resource
    private SearchApi searchApi;

    /**
     * 商品询价接口
     *
     * @param skuPriceBo
     * @return
     */
    public List<SkuBestPriceVo> querySkuPrice(QuerySkuPriceBo skuPriceBo) {
        ParamException.isTrue(CollectionUtils.isEmpty(skuPriceBo.getSkus()));
        //先根据Code查找没有找到在根据ID找
        List<Sku> skus = skuDao.selectByPrimaryKeys(skuPriceBo.getSkus().stream().map(QuerySkuPriceBo.Sku::getSkuId).collect(Collectors.toList()));
        ParamException.isTrue(CollectionUtils.isEmpty(skus));
        List<SkuBestPriceVo> skuBestPriceVos = skus.stream().map(sku -> {
            QuerySkuPriceBo.Sku sku1 = skuPriceBo.getSkus().stream().filter(o -> o.getSkuId().equals(sku.getId())).findFirst().orElse(null);
            SkuBestPriceVo skuBestPriceVo = new SkuBestPriceVo();
            skuBestPriceVo.setSkuId(sku.getId());
            skuBestPriceVo.setSkuDesc(sku.getItemSpecs());
            skuBestPriceVo.setSkuPic(sku.getImageUrl());
            skuBestPriceVo.setItemId(sku.getItemId());
            skuBestPriceVo.setPrice(sku.getRetailPrice());
            skuBestPriceVo.setRealPrice(sku.getRetailPrice());
            skuBestPriceVo.setFactoryPrice(sku.getFactoryPrice());
            skuBestPriceVo.setSkuCode(sku.getBarcode());
            skuBestPriceVo.setDeratePrice(BigDecimal.ZERO);
            skuBestPriceVo.setOtherSubsidyPrice(BigDecimal.ZERO);
            skuBestPriceVo.setSubsidyPrice(BigDecimal.ZERO);
            skuBestPriceVo.setSkuQty(sku1.getQty());
            skuBestPriceVo.setProfitPrice(BigDecimal.ZERO);
            skuBestPriceVo.setBargainOrderId(sku1.getBargainOrderId());
            skuBestPriceVo.setKillOrderId(sku1.getKillOrderId());
            return skuBestPriceVo;
        }).collect(Collectors.toList());
        List<ItemVo> list = itemService.getByItemIds(skuBestPriceVos.stream().map(SkuBestPriceVo::getItemId).collect(Collectors.toList()));
        list.forEach(itemVo -> {
            skuBestPriceVos.forEach(skuBestPriceVo -> {
                if (itemVo.getId().equals(skuBestPriceVo.getItemId())) {
                    skuBestPriceVo.setItemName(itemVo.getItemName());
                    skuBestPriceVo.setItemStatus(itemVo.getItemStatus());
                    skuBestPriceVo.setCategoryId(itemVo.getCategoryId());
                    skuBestPriceVo.setSpuCode(itemVo.getBarcode());
                    skuBestPriceVo.setSpuId(itemVo.getId());
                    skuBestPriceVo.setShopId(itemVo.getShopId());
                    skuBestPriceVo.setShopName(itemVo.getShopName());
                    skuBestPriceVo.setSupplierId(itemVo.getSupplierId());
                    skuBestPriceVo.setDiscountFlag(itemVo.getDiscountFlag());
                    skuBestPriceVo.setLimitTimeFlag(0);
                    skuBestPriceVo.setLimitQuantity(itemVo.getLimitQuantity());
                    skuBestPriceVo.setLimitFlag(itemVo.getLimitFlag());
                    skuBestPriceVo.setAgentFlag(itemVo.getAgentFlag());
                    skuBestPriceVo.setCharityFlag(itemVo.getCharityFlag());
                }
            });
        });
        reservePrice(skuBestPriceVos);
        //满减
        discountPrice(skuBestPriceVos);
        //限时购
        limitTimePrice(skuBestPriceVos);
        //打折商品价格
        discountItemPrice(skuBestPriceVos);
        //获取砍价价格
        bargainPrice(skuBestPriceVos);
        //获取秒杀价格
        killPrice(skuBestPriceVos);
        //获取津贴价格
        skuSubsidyAmount(skuBestPriceVos, skuPriceBo.getSubsidyAmount());
        //计算佣金
        //distPrice(skuBestPriceVos);
        return skuBestPriceVos;
    }

    /**
     * 计算佣金
     */
    private void distPrice(List<SkuBestPriceVo> skuBestPriceVos) {
        List<ComputeProfitPriceBo> computeProfitPriceVos = new ArrayList<>();
        skuBestPriceVos.forEach(orderSpuVo -> {
            if (StrUtil.isEmpty(orderSpuVo.getKillOrderId()) && StrUtil.isEmpty(orderSpuVo.getBargainOrderId())
                    && (orderSpuVo.getLimitTimeFlag() == null || orderSpuVo.getLimitTimeFlag() == 0) && (orderSpuVo.getDiscountFlag() == null || orderSpuVo.getDiscountFlag() == 0)) {
                ComputeProfitPriceBo computeProfitPriceBo = new ComputeProfitPriceBo();
                computeProfitPriceBo.setCategoryId(orderSpuVo.getCategoryId());
                computeProfitPriceBo.setSkuId(orderSpuVo.getSkuId());
                computeProfitPriceBo.setItemId(orderSpuVo.getItemId());
                computeProfitPriceBo.setPrice(orderSpuVo.getRealPrice());
                computeProfitPriceVos.add(computeProfitPriceBo);
            }
        });
        List<ComputeProfitPriceVo> profitPriceVos = goodsProfitService.computeProfitPrice(computeProfitPriceVos);
        profitPriceVos = profitPriceVos.stream().filter(o -> o.getProfitPrice() != null && o.getProfitPrice().compareTo(BigDecimal.ZERO) > 0).collect(Collectors.toList());
        for (SkuBestPriceVo skuBestPriceVo : skuBestPriceVos) {
            for (ComputeProfitPriceVo profitPriceVo : profitPriceVos) {
                if (skuBestPriceVo.getSkuId().equals(profitPriceVo.getSkuId())) {
                    skuBestPriceVo.setProfitPrice(profitPriceVo.getProfitPrice());
                }
            }
        }
    }

    /**
     * 计算商品可以抵扣津贴后的单价
     */
    private List<SkuBestPriceVo> skuSubsidyAmount(List<SkuBestPriceVo> skuBestPriceVos, BigDecimal subsidyAmount) {
        if (subsidyAmount == null) {
            return skuBestPriceVos;
        }
        //获取当前可用津贴的商品
        List<SkuBestPriceVo> orderSubsidyList = getOrderSubsidyList(skuBestPriceVos);
        //计算出一共可以用多少津贴
        BigDecimal orderSubsidyPrice = orderSubsidyList.stream().map(o -> o.getRealPrice().subtract(o.getFactoryPrice()).multiply(BigDecimal.valueOf(o.getSkuQty()))).reduce(BigDecimal.ZERO, BigDecimal::add);
        //计算出当前津贴比例
        BigDecimal subidyAvg = subsidyAmount.divide(orderSubsidyPrice, 5, RoundingMode.HALF_UP);
        subidyAvg = subidyAvg.compareTo(BigDecimal.ONE) > 0 ? BigDecimal.ONE : subidyAvg;
        for (SkuBestPriceVo sku : orderSubsidyList) {
            //计算出每个商品可用多少佣金
            sku.setSubsidyPrice(subidyAvg.multiply(sku.getRealPrice().subtract(sku.getFactoryPrice())).setScale(2, RoundingMode.HALF_UP).multiply(new BigDecimal(sku.getSkuQty())));
        }
        //计算出差值给最后一个商品
        BigDecimal chazhi = subsidyAmount.subtract(orderSubsidyList.stream().map(SkuBestPriceVo::getSubsidyPrice).reduce(BigDecimal.ZERO, BigDecimal::add));
        SkuBestPriceVo priceVo = orderSubsidyList.get(orderSubsidyList.size() - 1);
        priceVo.setSubsidyPrice(priceVo.getSubsidyPrice().add(chazhi));
        return skuBestPriceVos;
    }

    private void bargainPrice(List<SkuBestPriceVo> skuBestPriceVos) {
        skuBestPriceVos.forEach(skuBestPriceVo -> {
            if (StrUtil.isNotEmpty(skuBestPriceVo.getBargainOrderId())) {
                BargainOrder bo = bargainOrderDao.selectByPrimaryKey(skuBestPriceVo.getBargainOrderId());
                if (bo != null) {
                    skuBestPriceVo.setRealPrice(bo.getItemPrice().subtract(bo.getChoppedPrice()));
                    skuBestPriceVo.setDeratePrice(bo.getChoppedPrice());
                }
            }
        });
    }

    /**
     * 查询秒杀价格
     *
     * @param skuBestPriceVos
     */
    private void killPrice(List<SkuBestPriceVo> skuBestPriceVos) {
        skuBestPriceVos.forEach(skuBestPriceVo -> {
            if (StrUtil.isNotEmpty(skuBestPriceVo.getKillOrderId())) {
                SecondKillOrderVo bo = orderApi.getSeckillOrder(skuBestPriceVo.getKillOrderId()).getResult();
                if (bo != null) {
                    skuBestPriceVo.setRealPrice(bo.getSkuPrice());
                }
            }
        });
    }

    /**
     * 查询限时购价格
     *
     * @param skuBestPriceVos
     */
    private void limitTimePrice(List<SkuBestPriceVo> skuBestPriceVos) {
        Set<String> barcodeSet = skuBestPriceVos.stream().map(SkuBestPriceVo::getSkuCode).collect(Collectors.toSet());
        if (CollectionUtils.isEmpty(barcodeSet)) {
            return;
        }
        List<String> barcodes = new ArrayList<>(barcodeSet);
        QueryLimitTimePurGoodBo bo = new QueryLimitTimePurGoodBo();
        bo.setBarcodes(barcodes);
        bo.setIsEffect(1);
        bo.setIsNow(Instant.now());
        List<LimitTimePurGood> limitTimePurGoods1 = limitTimePurGoodDao.queryGood(bo);
        limitTimePurGoods1.forEach(dis -> skuBestPriceVos.forEach(skuBestPriceVo -> {
            if (dis.getBarcode().equals(skuBestPriceVo.getSkuCode())) {
                skuBestPriceVo.setRealPrice(dis.getLimitPrice());
                skuBestPriceVo.setProfitPrice(dis.getDistAmount());
                skuBestPriceVo.setSalesCount(dis.getSaleCount());
                skuBestPriceVo.setLimitCount(dis.getLimitCount());
                skuBestPriceVo.setLimitTimeFlag(1);
                ParamException.isTrue(dis.getDistAmount().compareTo(dis.getLimitPrice()) > 0, "价格异常");
            }
        }));
    }

    private void discountItemPrice(List<SkuBestPriceVo> skuBestPriceVos) {
        Set<String> barcodeSet = skuBestPriceVos.stream().filter(skuBestPriceVo -> BaseEnum.StatusEnum.ENABLE.getCode().equals(skuBestPriceVo.getDiscountFlag())).map(SkuBestPriceVo::getSkuCode).collect(Collectors.toSet());
        if (CollectionUtils.isEmpty(barcodeSet)) {
            return;
        }
        List<String> barcodes = new ArrayList<>(barcodeSet);
        List<DiscountItemSku> discountItemSkus = discountItemSkuDao.findListByBarcodes(barcodes);
        discountItemSkus.forEach(dis -> skuBestPriceVos.forEach(skuBestPriceVo -> {
            if (dis.getBarcode().equals(skuBestPriceVo.getSkuCode())) {
                skuBestPriceVo.setRealPrice(dis.getDiscountPrice());
                skuBestPriceVo.setDeratePrice(skuBestPriceVo.getPrice().subtract(skuBestPriceVo.getRealPrice()));
                if (null != dis.getItemCommission() && dis.getItemCommission().compareTo(skuBestPriceVo.getRealPrice()) > 0) {
                    skuBestPriceVo.setProfitPrice(skuBestPriceVo.getRealPrice());
                } else {
                    skuBestPriceVo.setProfitPrice(dis.getItemCommission());
                }
            }
        }));
    }

    /**
     * 商品减免询价
     *
     * @param skuBestPriceVos
     */
    private void discountPrice(List<SkuBestPriceVo> skuBestPriceVos) {
        List<ItemDiscountDto> discountDtos = discountDao.getItemDiscountDtos(skuBestPriceVos.stream().map(SkuBestPriceVo::getItemId).collect(Collectors.toSet()));
        Map<String, List<ItemDiscountDto>> activiMap = discountDtos.stream().collect(Collectors.groupingBy(ItemDiscountDto::getItemId));
        Map<String, ItemDiscountVo> discountVoMap = new HashMap<>();
        for (String key : activiMap.keySet()) {
            ItemDiscountVo discountVo = BeanConverUtils.convertBean(activiMap.get(key).get(0), ItemDiscountVo.class);
            Map<String, String> map = new HashMap<>();
            for (ItemDiscountDto discount : activiMap.get(key)) {
                map.put(discount.getDiscountNum().toString(), discount.getDiscountValue());
            }
            discountVo.setDiscountMap(map);
            discountVo.setItemId(key);
            discountVoMap.put(key, discountVo);
        }
        for (Map.Entry<String, ItemDiscountVo> entry : discountVoMap.entrySet()) {
            Integer quty = skuBestPriceVos.stream().filter(sku -> entry.getKey().equals(sku.getItemId())).mapToInt(SkuBestPriceVo::getSkuQty).sum();
            Map<String, String> dStringStringMap = entry.getValue().getDiscountMap();
            List<Integer> list = dStringStringMap.keySet().stream().filter(s -> quty >= Integer.valueOf(s)).map(s -> quty - Integer.valueOf(s)).collect(Collectors.toList());
            if (CollectionUtils.isEmpty(list)) {
                continue;
            }
            list.sort(Integer::compareTo);
            String finalDiscount = dStringStringMap.get(String.valueOf(quty - list.get(0)));
            skuBestPriceVos.stream().filter(sku -> entry.getKey().equals(sku.getItemId())).forEach(skuBestPriceVo -> {
                skuBestPriceVo.setRealPrice(skuBestPriceVo.getPrice().multiply(new BigDecimal(finalDiscount)).divide(new BigDecimal("10"), 2, BigDecimal.ROUND_UP));
                skuBestPriceVo.setDeratePrice(skuBestPriceVo.getPrice().subtract(skuBestPriceVo.getRealPrice()));
            });
        }

    }

    /**
     * 商品预购询价
     *
     * @param skuBestPriceVos
     */
    private void reservePrice(List<SkuBestPriceVo> skuBestPriceVos) {
        List<ItemReserveDto> reserveDtos = reserveDao.queryReserveByItemIds(skuBestPriceVos.stream().map(SkuBestPriceVo::getItemId).collect(Collectors.toSet()));
        for (ItemReserveDto itemReserveDto : reserveDtos) {
            if (itemReserveDto.getReserveEnd().isBefore(Instant.now()) || itemReserveDto.getReserveStart().isAfter(Instant.now())) {
                continue;
            }
            skuBestPriceVos.forEach(skuBestPriceVo -> {
                if (skuBestPriceVo.getItemId().equals(itemReserveDto.getItemId())) {
                    skuBestPriceVo.setRealPrice(skuBestPriceVo.getPrice().subtract(itemReserveDto.getReservePayDeduct()).add(itemReserveDto.getReservePay()));
                    List<SkuBestPriceVo.PhasePrice> phasePrices = new ArrayList<>();
                    SkuBestPriceVo.PhasePrice phasePrice = skuBestPriceVo.crePhasePrice();
                    phasePrice.setAmount(itemReserveDto.getReservePay());
                    phasePrice.setEndTime(itemReserveDto.getReserveEnd());
                    phasePrice.setStartTime(itemReserveDto.getReserveStart());
                    phasePrice.setPhase(0);
                    SkuBestPriceVo.PhasePrice phasePrice1 = skuBestPriceVo.crePhasePrice();
                    phasePrice1.setAmount(skuBestPriceVo.getRealPrice().subtract(phasePrice.getAmount()));
                    phasePrice1.setEndTime(itemReserveDto.getRestPayEndDate());
                    phasePrice1.setStartTime(itemReserveDto.getRestPayStartDate());
                    phasePrice1.setPhase(1);
                    phasePrices.add(phasePrice);
                    phasePrices.add(phasePrice1);
                    skuBestPriceVo.setPhasePrices(phasePrices);
                }
            });
        }
    }


    public PageVo<SkuVo> page(PageBo<SkuBo> pageBo) {
        PageHelper.startPage(pageBo.getPage(), pageBo.getPageSize(), MySqlUtil.orderBy(pageBo.getSort(), pageBo.isAsc()));
        Sku sku = BeanConverUtils.convertBean(pageBo.getParam(), Sku.class);
        PageInfo info = new PageInfo(skuDao.select(sku));
        return new PageVo<>(info.getTotal(), pageBo.getPage(), pageBo.getPageSize(), BeanConverUtils.convertBeanList(info.getList(), SkuVo.class));
    }

    public List<SkuVo> index(PageBo<SkuBo> pageBo) {
        PageHelper.startPage(pageBo.getPage(), pageBo.getPageSize(), MySqlUtil.orderBy(pageBo.getSort(), pageBo.isAsc()));
        Sku sku = BeanConverUtils.convertBean(pageBo.getParam(), Sku.class);
        PageInfo info = new PageInfo(skuDao.select(sku));
        return BeanConverUtils.convertBeanList(info.getList(), SkuVo.class);
    }


    public PageVo<SkuVo> indexApi(PageBo<ItemListApiBo> pageBo) {
        ParamException.isTrue(pageBo.getParam().getAppId() == null, "appID不能为空");
        ParamException.isTrue(pageBo.getParam().getTimestamp() == null, "请求时间为空");
        SupplierBo supplierBo = new SupplierBo();
        supplierBo.setAppId(pageBo.getParam().getAppId());
        List<SupplierVo> data = supplierService.getList(supplierBo);
        ParamException.isTrue(data == null || data.size() == 0, "appID不存在");
        List<String> supplierList = data.stream().map(supplierVo -> {
            return supplierVo.getId();
        }).collect(Collectors.toList());
        //ParamException.isFalse(ThirdPartEnum.ThirdPartCode.isIncludeCode(pageBo.getParam().getAppId()),"appID不存在或者已过期");
        PageHelper.startPage(pageBo.getPage(), pageBo.getPageSize(), MySqlUtil.orderBy(pageBo.getSort(), pageBo.isAsc()));
        ItemListApiBo bo = pageBo.getParam();
        bo.setSupplierList(supplierList);
        PageInfo info = new PageInfo(skuDao.querySkuList(bo));
        List<SkuVo> list = BeanConverUtils.convertBeanList(info.getList(), SkuVo.class);
        PageVo<SkuVo> skuVoPageVo = new PageVo<>(info.getTotal(), pageBo.getPage(), pageBo.getPageSize(), list);
        return skuVoPageVo;
    }

    @Transactional(rollbackFor = Throwable.class)
    public void delete(String id) {
        skuDao.deleteById(id);
    }


    public SkuVo detail(String id) {
        return BeanConverUtils.convertBean(skuDao.selectByPrimaryKey(id), SkuVo.class);
    }

    public SkuVo detailWithBarcode(String barcode) {
        Sku sku = new Sku();
        sku.setBarcode(barcode);
        return BeanConverUtils.convertBean(skuDao.selectOne(sku), SkuVo.class);
    }

    public void updateByBatch(List<SkuBo> skuBo) {
        skuDao.updateByBatch(skuBo);
    }

    public void updateStockAndPrice(List<SkuBo> skuBo) {
        skuDao.updateStockAndPrice(skuBo);
    }

    public void changeSales(ChangeStockBo changeStockBo) {
        Map<String, Integer> map = changeStockBo.getSkus();
        if (changeStockBo.getType() == 1) {
            for (Map.Entry<String, Integer> entry : map.entrySet()) {
                SkuVo sku = getByBarCode(entry.getKey());
                //商品销量更新
                Item item = itemDao.selectByPrimaryKey(sku.getItemId());
                item.setSales(item.getSales() + entry.getValue());
                item.setSumSales(item.getSales() + item.getFalseSales());
                itemDao.updateSales(item.getId(), item.getSales(), item.getSumSales());
            }
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public void changeStock(ChangeStockBo changeStockBo) {
        log.info("changeStock param :[{}]", JSON.toJSONString(changeStockBo));
        List<SkuBo> skuBoList = new ArrayList<>();
        Map<String, Integer> itemStockMap = new HashMap<>();
        Map<String, Integer> skuStockMap = new HashMap<>();
        Map<String, Integer> map = changeStockBo.getSkus();
        if (changeStockBo.getType() == 1) {
            for (Map.Entry<String, Integer> entry : map.entrySet()) {
                SkuVo skuVo = getByBarCode(entry.getKey());
                if (null != skuVo) {
                    SkuBo skuBo = new SkuBo();
                    setStock(itemStockMap, skuVo.getItemId(), Math.negateExact(entry.getValue()));
                    setStock(skuStockMap, skuVo.getBarcode(), Math.negateExact(entry.getValue()));
                    if ((skuVo.getStock() - (skuVo.getLockStock() == null ? 0 : skuVo.getLockStock())) >= entry.getValue()) {
                        skuBo.setId(skuVo.getId());
                        skuBo.setStock(skuVo.getStock() - entry.getValue());
                        skuBoList.add(skuBo);
                    } else {
                        throw new CommonException(ExceptionCode.STOCK_NOT_ENOUGH);
                    }
                }
            }
        }
        if (changeStockBo.getType() == 0) {
            for (Map.Entry<String, Integer> entry : map.entrySet()) {
                SkuVo skuVo = getByBarCode(entry.getKey());
                if (null != skuVo) {
                    SkuBo skuBo = new SkuBo();
                    setStock(itemStockMap, skuVo.getItemId(), entry.getValue());
                    setStock(skuStockMap, skuVo.getBarcode(), entry.getValue());
                    skuBo.setId(skuVo.getId());
                    skuBo.setStock(skuVo.getStock() + entry.getValue());
                    skuBoList.add(skuBo);
                }
            }
        }
        if (!CollectionUtils.isEmpty(itemStockMap)) {
            updateItemStock(itemStockMap);
        }
        if (!CollectionUtils.isEmpty(skuBoList)) {
            updateByBatch(skuBoList);
        }
        //打折商品
        if (new Integer(4).equals(changeStockBo.getOrderType())) {
            List<SkuSaleBo> skuSaleList = changeStockBo.getSkuSaleList();
            List<String> itemIds = new ArrayList<>(skuSaleList.stream().map(SkuSaleBo::getItemId).collect(Collectors.toSet()));
            List<DiscountItem> discountItems = discountItemDao.getListByItemIds(itemIds);
            if (!CollectionUtils.isEmpty(discountItems)) {
                updateDiscountItemStock(itemStockMap, discountItems);
                updateDiscountItemSkuStock(skuStockMap);
                ((SkuService) AopContext.currentProxy()).changeDiscountItemSales(changeStockBo, discountItems);
            }
        }
        if (new Integer(3).equals(changeStockBo.getOrderType())) {
            //变更销量
            ((SkuService) AopContext.currentProxy()).changeLimitItemSales(changeStockBo);
        }
    }

    /**
     * 变更销量
     */
    @Async
    public void changeLimitItemSales(ChangeStockBo changeStockBo) {
        if ((new Integer(3).equals(changeStockBo.getOrderType()))) {
            limitTimePurActiveService.updateOrder(changeStockBo);
        }
    }

    @Async
    public void changeDiscountItemSales(ChangeStockBo changeStockBo, List<DiscountItem> discountItems) {
        List<SkuSaleBo> skuSaleList = changeStockBo.getSkuSaleList();
        List<DiscountItemSaleBo> list = new ArrayList<>();
        if (!CollectionUtils.isEmpty(skuSaleList)) {
            skuSaleList.forEach(skuSaleDto -> {
                DiscountItem discountItem = discountItems.stream().filter(di -> skuSaleDto.getItemId().equals(di.getItemId())).findFirst().orElse(null);
                if (null != discountItem) {
                    Integer sales = null == discountItem.getSales() ? 0 : discountItem.getSales();
                    Integer orderNum = null == discountItem.getOrderNum() ? 0 : discountItem.getOrderNum();
                    BigDecimal orderAmount = null == discountItem.getOrderAmount() ? BigDecimal.ZERO : discountItem.getOrderAmount();
                    DiscountItemSaleBo disBo = list.stream().filter(discountItemSaleBo -> discountItem.getId().equals(discountItemSaleBo.getId())).findFirst().orElse(null);
                    if (null == disBo) {
                        disBo = new DiscountItemSaleBo();
                        disBo.setId(discountItem.getId());
                        disBo.setItemId(skuSaleDto.getItemId());
                        if (1 == changeStockBo.getType()) {
                            disBo.setSales(sales + skuSaleDto.getSkuQty());
                            disBo.setOrderNum(orderNum + 1);
                            disBo.setOrderAmount(orderAmount.add(skuSaleDto.getRealPrice().multiply(new BigDecimal(skuSaleDto.getSkuQty()))));
                        } else {
                            Integer sumSales = sales - skuSaleDto.getSkuQty();
                            Integer sumOrderNum = orderNum - 1;
                            BigDecimal sumOrderAmount = orderAmount.subtract(skuSaleDto.getRealPrice().multiply(new BigDecimal(skuSaleDto.getSkuQty())));
                            disBo.setSales(sumSales > 0 ? sumSales : 0);
                            disBo.setOrderNum(sumOrderNum > 0 ? sumOrderNum : 0);
                            disBo.setOrderAmount(sumOrderAmount.compareTo(BigDecimal.ZERO) > 0 ? sumOrderAmount : BigDecimal.ZERO);
                        }
                        list.add(disBo);
                    } else {
                        if (1 == changeStockBo.getType()) {
                            disBo.setSales(disBo.getSales() + skuSaleDto.getSkuQty());
                            disBo.setOrderAmount(disBo.getOrderAmount().add(skuSaleDto.getRealPrice().multiply(new BigDecimal(skuSaleDto.getSkuQty()))));
                        } else {
                            disBo.setSales(disBo.getSales() - skuSaleDto.getSkuQty());
                            disBo.setOrderAmount(disBo.getOrderAmount().subtract(skuSaleDto.getRealPrice().multiply(new BigDecimal(skuSaleDto.getSkuQty()))));
                        }
                    }
                }
            });
            discountItemDao.updateSale(list);
        }
    }

    private void updateItemStock(Map<String, Integer> stockMap) {
        if (CollectionUtils.isEmpty(stockMap) || CollectionUtils.isEmpty(stockMap.keySet())) {
            return;
        }
        List<Item> list = itemDao.findItemListByIds(new ArrayList<>(stockMap.keySet()));
        if (!CollectionUtils.isEmpty(list)) {
            List<Item> itemList = new ArrayList<>();
            list.forEach(item -> {
                Integer changeStock = stockMap.getOrDefault(item.getId(), 0);
                Integer stock = item.getStock() + changeStock;
                Item entity = new Item();
                entity.setId(item.getId());
                if (stock <= 0) {
                    entity.setStock(0);
                } else {
                    entity.setStock(stock);
                }
                itemList.add(entity);
            });
            itemDao.batchUpdateStock(itemList);
        }
    }

    private void updateDiscountItemStock(Map<String, Integer> stockMap, List<DiscountItem> discountItems) {
        if (!CollectionUtils.isEmpty(discountItems)) {
            List<DiscountItemChangeStockBo> boList = new ArrayList<>();
            List<String> itemIds = new ArrayList<>();
            discountItems.forEach(item -> {
                Integer stock = item.getStock() + stockMap.getOrDefault(item.getItemId(), 0);
                DiscountItemChangeStockBo bo = new DiscountItemChangeStockBo();
                bo.setId(item.getId());
                if (stock <= 0) {
                    bo.setStatus(BaseEnum.StatusEnum.DISABLE.getCode());
                    bo.setStock(0);
                    itemIds.add(item.getItemId());
                } else {
                    bo.setStatus(BaseEnum.StatusEnum.ENABLE.getCode());
                    bo.setStock(stock);
                }
                boList.add(bo);
            });
            if (!CollectionUtils.isEmpty(boList)) {
                discountItemDao.batchUpdateStock(boList);
            }
            updateItemDiscount(itemIds);
        }
    }

    private void updateDiscountItemSkuStock(Map<String, Integer> stockMap) {
        List<DiscountItemSku> list = discountItemSkuDao.findListByBarcodes(new ArrayList<>(stockMap.keySet()));
        if (CollectionUtils.isEmpty(list)) {
            return;
        }
        List<DiscountItemSku> updateList = new ArrayList<>();
        list.forEach(dis -> {
            Integer stock = dis.getStock() + stockMap.getOrDefault(dis.getBarcode(), 0);
            DiscountItemSku discountItemSku = new DiscountItemSku();
            discountItemSku.setId(dis.getId());
            if (stock <= 0) {
                discountItemSku.setStock(0);
                discountItemSku.setSkuStatus(BaseEnum.StatusEnum.DISABLE.getCode());
            } else {
                discountItemSku.setStock(stock);
                discountItemSku.setSkuStatus(BaseEnum.StatusEnum.ENABLE.getCode());
            }
            updateList.add(discountItemSku);
        });
        discountItemSkuDao.batchUpdateStock(updateList);
    }

    private void updateItemDiscount(List<String> itemIds) {
        if (!CollectionUtils.isEmpty(itemIds)) {
            itemTagDao.deleteByItemIdsAndCode(itemIds, GoodsEnum.ItemTagEnum.DISCOUNT.getCode());
            List<ItemTag> itemTagList = itemTagDao.findByItemIds(itemIds);
            List<Sku> skus = skuDao.findByItemIds(itemIds, BaseEnum.StatusEnum.ENABLE.getCode());
            List<Item> items = new ArrayList<>();
            itemIds.forEach(itemId -> {
                Item item = new Item();
                item.setId(itemId);
                Sku sku1 = skus.stream().filter(sku -> itemId.equals(sku.getItemId())).min(Comparator.comparing(Sku::getRetailPrice)).orElse(null);
                if (null != sku1) {
                    item.setOriginPrice(sku1.getRetailPrice());
                    item.setItemCommission(sku1.getItemCommission());
                }
                List<ItemTag> tags = itemTagList.stream().filter(itemTag -> itemId.equals(itemTag.getItemId())).collect(Collectors.toList());
                item.setItemSgin(getItemTagString(tags));
                item.setDiscountFlag(BaseEnum.StatusEnum.DISABLE.getCode());
                items.add(item);
            });
            itemDao.batchUpdateItemDiscountInfo(items);
            ((SkuService) AopContext.currentProxy()).batchSyncSearch(itemIds);
        }
    }

    @Async
    public void batchSyncSearch(List<String> itemIds) {
        itemIds.forEach(itemId -> {
            ItemVo itemVo = BeanConverUtils.convertBean(itemDao.selectByPrimaryKey(itemId), ItemVo.class);
            searchApi.create(itemVo);
        });
    }

    private String getItemTagString(List<ItemTag> list) {
        StringJoiner sj = new StringJoiner(",");
        list.forEach(itemTag -> {
            sj.add(itemTag.getName());
        });
        return sj.toString();
    }

    private void setStock(Map<String, Integer> stockMap, String key, Integer stock) {
        if (stockMap.containsKey(key)) {
            Integer oldStock = stockMap.get(key);
            stockMap.put(key, oldStock + stock);
        } else {
            stockMap.put(key, stock);
        }
    }

    @Transactional(rollbackFor = Throwable.class)
    public void lockStock(LockStockBo lockStockBo) {
        if (lockStockBo.getOldLockStock() == null) {
            lockStockBo.setOldLockStock(0);
        }
        if (lockStockBo.getNewLockStock() == null) {
            lockStockBo.setNewLockStock(0);
        }
        Sku sku11 = new Sku();
        sku11.setBarcode(lockStockBo.getBarcode());
        Sku sku = skuDao.selectOne(sku11);
        Sku sku1 = new Sku();
        sku1.setId(sku.getId());
        sku1.setLockStock(sku.getLockStock() - lockStockBo.getOldLockStock() + lockStockBo.getNewLockStock());
        int i = skuDao.updateByPrimaryKeySelective(sku1);
        //ParamException.isTrue(i<1,"更新锁定库存失败,商品barcode"+sku.getBarcode());
    }

    public String checkLockStock(LockStockBo lockStockBo) {
        if (!StringUtils.hasText(lockStockBo.getBarcode())) {
            return "barcode为空";
        }
        Sku sku11 = new Sku();
        sku11.setBarcode(lockStockBo.getBarcode());
        Sku sku = skuDao.selectOne(sku11);
        if (sku == null) {
            return "barcode不存在";
        }
        if ((sku.getStock() == null ? 0 : sku.getStock())
                - (sku.getLockStock() - lockStockBo.getOldLockStock() + lockStockBo.getNewLockStock()) < 0) {
            return ExceptionCode.STOCK_NOT_ENOUGH.getMsg();
        }
        return null;
    }

    /**
     * 同步库存数量api
     *
     * @param bo
     */
    @Transactional(rollbackFor = Exception.class)
    public void updateRealStock(ItemListApiBo bo) {
        ParamException.isTrue(bo.getAppId() == null, "appID不能为空");
        ParamException.isTrue(bo.getTimestamp() == null, "请求时间为空");
        SupplierBo supplierBo = new SupplierBo();
        supplierBo.setAppId(bo.getAppId());
        List<SupplierVo> data = supplierService.getList(supplierBo);
        ParamException.isTrue(data == null || data.size() == 0, "appID不存在");
        List<String> supplierList = data.stream().map(supplierVo -> {
            return supplierVo.getId();
        }).collect(Collectors.toList());
        //ParamException.isFalse(ThirdPartEnum.ThirdPartCode.isIncludeCode(bo.getAppId()),"appID不存在或者已过期");
        bo.setSupplierList(supplierList);
        //ParamException.isTrue(bo.getSkuId()==null,"子商品skuid为空");
        ParamException.isTrue(bo.getBarcode() == null, "barcode为空");
        ParamException.isTrue(bo.getRealStock() == null, "实库数量为空");
        skuDao.updateRealStock(bo);
    }

    public List<SkuVo> getByBarCodeList(List<String> codeList) {
        List<Sku> skuList = skuDao.getByBarCodeList(codeList);
        return BeanConverUtils.convertBeanList(skuList, SkuVo.class);
    }

    public SkuVo getByBarCode(String barcode) {
        return BeanConverUtils.convertBean(skuDao.findByBarCode(barcode), SkuVo.class);
    }

    /**
     * 获取可以参与津贴计算的商品
     * 没有津贴价格或者津贴价格小于0的不参与津贴减免
     * 津贴价格大于实际价格的商品不参与减免
     *
     * @param skuBestPriceVo
     */
    private List<SkuBestPriceVo> getOrderSubsidyList(List<SkuBestPriceVo> skuBestPriceVo) {
        //可以参加津贴抵扣的商品
        List<SkuBestPriceVo> skuSubsidyPriceVo = skuBestPriceVo.stream().filter(o -> {
            if (o.getFactoryPrice() == null) {
                return false;
            }
            if (o.getFactoryPrice().compareTo(BigDecimal.ZERO) <= 0) {
                return false;
            }
            return o.getRealPrice().compareTo(o.getFactoryPrice()) > 0;
        }).collect(Collectors.toList());
        return skuSubsidyPriceVo;
    }

    public List<SkuVo> getSkuListByBarcodes(List<String> list) {
        List<SkuVo> byBarCodes = BeanConverUtils.convertBeanList(skuDao.findByBarCodes(list), SkuVo.class);
        return byBarCodes;
    }

    public List<String> querySkuIds(Collection<String> itemIds) {
        return skuDao.findByItemIds(itemIds, null).stream().map(Sku::getId).collect(Collectors.toList());
    }
}
